
#ifndef SX_CONTROLLER_H
#define SX_CONTROLLER_H

#include <sxArrayList.h>
#include <sxControllerListener.h>

namespace Sx {

template <typename ControlledType>
class Controller {
public:
	Controller(ControlledType* object);
	virtual ~Controller();

	bool addListener(ControllerListener<ControlledType>* listener);
	bool removeListener(ControllerListener<ControlledType>* listener);

	bool acquire(ControlledType* object);
	bool release();
	bool hasObject() const;

protected:
	/* POINTER_OWNERSHIP: NO */
	ControlledType* object;

	/* POINTER_OWNERSHIP: NO */
	Util::ArrayList<ControllerListener<ControlledType>* > listeners;
};

}

template <typename ControlledType>
Sx::Controller<ControlledType>::Controller(ControlledType* object) {
	this->object = object;
}

template <typename ControlledType>
Sx::Controller<ControlledType>::~Controller() {
	/* this->object not owned by this class */

	//--------------------------------------------------------------------------
	// Listener pointers not owned by this class. Inform all of the listeners
	// that this object is being destructed and then clear the list.
	//--------------------------------------------------------------------------
	this->release();
	this->listeners.clear();
}

template <typename ControlledType>
bool Sx::Controller<ControlledType>::addListener(ControllerListener<ControlledType>* listener) {
	if ( listener == nullptr ) {
		std::cerr << "[Controller:addListener] Error: Cannot add nullptr listener to controller." << std::endl;
		std::cerr << "  Listener not added to controller." << std::endl;
		return false;
	}

	//--------------------------------------------------------------------------
	// Check to see if this listener is already registered with this controller
	//--------------------------------------------------------------------------
	if ( this->listeners.contains(listener) ) {
		std::cerr << "[Controller:addListener] Error: This controller already contains this listener." << std::endl;
		std::cerr << "  Listener not added to controller." << std::endl;
		return false;
	}

	this->listeners.add(listener);
	return true;
}

template <typename ControlledType>
bool Sx::Controller<ControlledType>::removeListener(ControllerListener<ControlledType>* listener) {
	if ( listener == nullptr ) {
		std::cerr << "[Controller:removeListener] Error: Cannot remove nullptr listener from controller." << std::endl;
		std::cerr << "  Listener not removed to controller." << std::endl;
		return false;
	}

	return this->listeners.remove(listener);
}

template <typename ControlledType>
bool Sx::Controller<ControlledType>::acquire(ControlledType* object) {
	this->object = object;
	for ( unsigned int i = 0; i < this->listeners.size(); i++ )
		this->listeners[i]->onAcquire(this->object);
	return true;
}

template <typename ControlledType>
bool Sx::Controller<ControlledType>::release() {
	for ( unsigned int i = 0; i < this->listeners.size(); i++ )
		this->listeners[i]->onRelease();
	return true;
}

template <typename ControlledType>
bool Sx::Controller<ControlledType>::hasObject() const {
	if ( this->object == nullptr ) return false;
	return true;
}

#endif
